跳到主要内容

Spring Bean 生命周期常见的拓展点

Bean 的生命周期一览

Bean 也可以生命周期中拓展,所以对于这些拓展点还是需要了解的

Bean 的生命周期作用如下所示:

1、Bean 容器找到配置文件中 Spring Bean 的定义。

2、Bean 容器利用 Java Reflection API 创建一个 Bean 的实例。

3、如果涉及到一些属性值 利用 set() 方法设置一些属性值。

4、如果 Bean 实现了 BeanNameAware 接口,调用 setBeanName() 方法,传入 Bean 的名字。

5、如果 Bean 实现了 BeanClassLoaderAware 接口,调用 setBeanClassLoader() 方法,传入 ClassLoader对象的实例。

6、与上面的类似,如果实现了其他 *.Aware 接口,就调用相应的方法。

7、如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor 对象,执行 postProcessBeforeInitialization() 方法

8、如果 Bean 实现了 InitializingBean 接口,执行 afterPropertiesSet() 方法。

9、如果 Bean 在配置文件中的定义包含 init-method 属性,执行指定的方法。

10、如果有和加载这个 Bean的 Spring 容器相关的 BeanPostProcessor 对象,执行 postProcessAfterInitialization() 方法

11、当要销毁 Bean 的时候,如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。

12、当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法。

上文如下图所示:

整个流程一览

第一大类:影响多个 Bean 的接口

实现了这些接口的 Bean 会切入到多个 Bean 的生命周期中。正因为如此,这些接口的功能非常强大,Spring 内部扩展也经常使用这些接口,例如自动注入以及 AOP 的实现都和他们有关。

  • InstantiationAwareBeanPostProcessor
  • BeanPostProcessor

它们是 Spring 扩展中最重要的两个接口!

InstantiationAwareBeanPostProcessor 作用于实例化阶段的前后,而 BeanPostProcessor 作用于初始化阶段的前后。

它们正好和第一、第三个生命周期阶段对应。通过图能更好理解:

InstantiationAwareBeanPostProcessor 实际上继承了 BeanPostProcessor 接口,严格意义上来看他们不是两兄弟,而是两父子。但是从生命周期角度我们重点关注其特有的对实例化阶段的影响,图中省略了从 BeanPostProcessor 继承的方法。

InstantiationAwareBeanPostProcessor extends BeanPostProcessor

InstantiationAwareBeanPostProcessor 接口

这里先讲 InstantiationAwareBeanPostProcessor 接口的内容,关于 BeanPostProcessor 执行阶段的源码穿插在下文 Aware 接口的调用时机分析中,因为部分 Aware 功能的就是通过他实现的! 只需要先记住 BeanPostProcessor 在初始化前后调用就可以了。

InstantiationAwareBeanPostProcessor 接口有两个调用点,分别是 postProcessBeforeInstantiation 和 postProcessAfterInstantiation 它们的调用时间就像它们的名字一样,位于实例化的前后执行,一般用于处理 AOP 相关的东西

下面这是 postProcessBeforeInstantiation 调用点,忽略无关代码:

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {

try {
// 让 BeanPostProcessors 可以返回一个代理而不是目标 bean 实例。
// for 循环调用所有的 InstantiationAwareBeanPostProcessor
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}

try {
// postProcessBeforeInstantiation 方法在创建 Bean 之前调用
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
}

如上可见 postProcessBeforeInstantiation 在 doCreateBean 之前调用,也就是在 bean 实例化之前调用的,该方法的返回值可能会替换原本的 Bean 作为代理,这也是 Aop 等功能实现的关键点。

下面这是 postProcessAfterInstantiation 调用点,忽略无关代码:

这个是在 doCreateBean 中被调用的,具体看上面的 doCreateBean 方法

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {

boolean continueWithPropertyPopulation = true;

// 方法作为属性赋值的前置检查条件,在属性赋值之前执行,能够影响是否进行属性赋值!
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;

if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
// postProcessAfterInstantiation 默认返回 true
continueWithPropertyPopulation = false;
break;
}
}
}
}

if (!continueWithPropertyPopulation) {
return;
}

// 忽略后续的属性赋值操作代码
}

可以看到该方法在属性赋值方法内,但是在真正执行赋值操作之前。其返回值为 boolean,返回 false 时可以阻断后面属性赋值阶段(continueWithPropertyPopulation = false;)。

BeanPostProcessor 注册时机

实现了 BeanPostProcessor 接口的实例也会注册为 Bean,那么 Spring 是如何保证 BeanPostProcessor 在我们的业务 Bean 之前初始化完成呢?

Spring 容器启动时会创建 IOC 容器,在创建容器时,会调用 refresh() 方法,整个容器就是通过该方法,完成所有的 bean 的创建以及初始化

@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
// 所有 BeanPostProcessor 初始化的调用点
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
initMessageSource();

// Initialize event multicaster for this context.
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
onRefresh();

// Check for listener beans and register them.
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
// 所有单例非懒加载Bean的调用点
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.

finishRefresh();
}
}

可以看出,Spring 是先执行 registerBeanPostProcessors() 进行 BeanPostProcessors 的注册,然后再执行 finishBeanFactoryInitialization 初始化我们的单例非懒加载的 Bean

BeanPostProcessor 执行顺序

BeanPostProcessor 有很多个,而且每个 BeanPostProcessor 都影响多个Bean,其执行顺序至关重要,必须能够控制其执行顺序才行。关于执行顺序这里需要引入两个排序相关的接口:PriorityOrdered、Ordered

PriorityOrdered 是一等公民,首先被执行,PriorityOrdered 公民之间通过接口返回值排序

Ordered 是二等公民,然后执行,Ordered 公民之间通过接口返回值排序

都没有实现是三等公民,最后执行

在以下源码中,可以很清晰的看到 Spring 注册各种类型 BeanPostProcessor 的逻辑,根据实现不同排序接口进行分组。优先级高的先加入,优先级低的后加入

// 首先,加入实现了 PriorityOrdered 接口的 BeanPostProcessors,顺便根据 PriorityOrdered 排了序
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}

sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();


// 然后,加入实现了 Ordered 接口的 BeanPostProcessors,顺便根据 Ordered 排了序
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}

sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();


// 最后加入其他常规的 BeanPostProcessors
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}

sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}

根据排序接口返回值排序,默认升序排序,返回值越低优先级越高。

/**
* Useful constant for the highest precedence value.
* @see java.lang.Integer#MIN_VALUE
*/
int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;

/**
* Useful constant for the lowest precedence value.
* @see java.lang.Integer#MAX_VALUE
*/
int LOWEST_PRECEDENCE = Integer.MAX_VALUE;

第二大类:只调用一次的接口

这一大类接口的特点是功能丰富,常用于用户自定义扩展。 第二大类中又可以分为两类:

  1. Aware类型的接口
  2. 生命周期接口

Aware 类型接口

Aware 类型的接口的作用就是让我们能够拿到 Spring 容器中的一些资源。基本都能够见名知意,Aware 之前的名字就是可以拿到什么资源,例如BeanNameAware 可以拿到 BeanName,以此类推。

调用时机需要注意:所有的 Aware 方法都是在初始化阶段之前调用的!

下面以 Aware 接口的执行顺序排序

Aware Group1

1、BeanNameAware

2、BeanClassLoaderAware

3、BeanFactoryAware

Aware Group2

4、EnvironmentAware

5、EmbeddedValueResolverAware 实现该接口能够获取 Spring EL 解析器,用户的自定义注解需要支持 SpringEL 表达式的时候可以使用

6、ApplicationContextAware(ResourceLoaderAware \ApplicationEventPublisherAware \MessageSourceAware)这几个接口返回的都是当前的 ApplicationContext 对象,因为 ApplicationContext 是一个复合接口

如下所示:

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {}

Aware 调用时机源码分析

详情如下,忽略了部分无关代码。代码位置就是上文提到的 initializeBean 方法详情,这也说明了 Aware 都是在初始化阶段之前调用的!

// 见名知意,初始化阶段调用的方法
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {

// 这里调用的是 Group1 中的三个 Bean 开头的 Aware
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;

// 这里调用的是 Group2 中的几个 Aware,
// 而实质上这里就是前面所说的 BeanPostProcessor 的调用点!
// 也就是说与 Group1 中的 Aware 不同,这里是通过 BeanPostProcessor(ApplicationContextAwareProcessor)实现的。
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);

// 下文即将介绍的 InitializingBean 调用点
invokeInitMethods(beanName, wrappedBean, mbd);
// BeanPostProcessor 的另一个调用点
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
return wrappedBean;
}

可以看到并不是所有的 Aware 接口都使用同样的方式调用。

Bean××Aware 都是在代码中直接调用的,而 ApplicationContext 相关的 Aware 都是通过 BeanPostProcessor#postProcessBeforeInitialization() 实现的。感兴趣的可以自己看一下 ApplicationContextAwareProcessor 这个类的源码,就是判断当前创建的 Bean 是否实现了相关的 Aware 方法,如果实现了会调用回调方法将资源传递给Bean。

至于 Spring 为什么这么实现,应该没什么特殊的考量。也许和 Spring 的版本升级有关。基于对修改关闭,对扩展开放的原则,Spring 对一些新的 Aware 采用了扩展的方式添加。

BeanPostProcessor 的调用时机也能在这里体现,包围住 invokeInitMethods 方法,也就说明了在初始化阶段的前后执行。

关于 Aware 接口的执行顺序,其实只需要记住第一组在第二组执行之前就行了。每组中各个 Aware 方法的调用顺序其实没有必要记,有需要的时候点进源码一看便知。

初始和销毁阶段生命周期类接口

至于剩下的两个生命周期接口就很简单了,实例化和属性赋值都是 Spring 帮助我们做的,能够自己实现的有初始化和销毁两个生命周期阶段。

InitializingBean 接口对应生命周期的初始化阶段,在上面源码的

invokeInitMethods(beanName, wrappedBean, mbd);

方法中调用。

有一点需要注意,因为 Aware 方法都是执行在初始化方法之前,所以可以在初始化方法中放心大胆的使用 Aware 接口获取的资源,这也是我们自定义扩展 Spring 的常用方式。

除了实现 InitializingBean 接口之外还能通过注解或者 xml 配置的方式指定初始化方法,至于这几种定义方式的调用顺序其实没有必要记。因为这几个方法对应的都是同一个生命周期,只是实现方式不同,我们一般只采用其中一种方式。

DisposableBean 类似于 InitializingBean,对应生命周期的销毁阶段,以 ConfigurableApplicationContext#close() 方法作为入口,实现是通过循环取所有实现了 DisposableBean 接口的 Bean 然后调用其 destroy() 方法 。

生命周期总结

Spring Bean 的生命周期分为四个阶段和多个扩展点。

扩展点又可以分为影响多个 Bean 和影响单个 Bean。整理如下:

四个阶段 ⭐

  • 实例化 Instantiation:包装对象,执行构造方法,用于提前暴露实例解决循环依赖问题
  • 属性赋值 Populate:寻找并且注入依赖,依赖的 Bean 还会递归调用 getBean 方法获取)
  • 初始化 Initialization:调用自定义的初始化方法(不是构造方法,而是调用 <bean>init-method 属性指定的初始化方法))
  • 销毁 Destruction

多个扩展点

影响多个 Bean 的拓展点

  • BeanPostProcessor
  • InstantiationAwareBeanPostProcessor

影响单个 Bean 的拓展点

Aware Group1

  • BeanNameAware
  • BeanClassLoaderAware
  • BeanFactoryAware

Aware Group2

  • EnvironmentAware
  • EmbeddedValueResolverAware
  • ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware)

生命周期

  • InitializingBean
  • DisposableBean

Bean 生命周期总结

Bean 的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:

1、Bean自身的方法:这个包括了 Bean 本身调用的方法和通过配置文件中 bean 的 init-method 和 destroy-method 指定的方法

2、Bean 级生命周期接口方法:这个包括了 BeanNameAware、BeanFactoryAware、InitializingBean和 DiposibleBean 这些接口的方法

3、容器级生命周期接口方法:这个包括了 InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为 “后处理器”。

4、工厂后处理器接口方法:这个包括了 AspectJWeavingEnabler,ConfigurationClassPostProcessor,CustomAutowireConfigurer 等等非常有用的工厂后处理器接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。

具体使用示例 ⭐

Bean 级生命周期接口方法

用一个简单的 Spring Bean 来演示一下 Spring Bean 的生命周期。

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class Person implements BeanFactoryAware, BeanNameAware,
InitializingBean, DisposableBean {

private String name;
private String address;
private int phone;

private BeanFactory beanFactory;
private String beanName;

public Person() {
System.out.println("【构造器】调用Person的构造器实例化");
}

public String getName() {
return name;
}

public void setName(String name) {
System.out.println("【注入属性】注入属性name");
this.name = name;
}

public String getAddress() {
return address;
}

public void setAddress(String address) {
System.out.println("【注入属性】注入属性address");
this.address = address;
}

public int getPhone() {
return phone;
}

public void setPhone(int phone) {
System.out.println("【注入属性】注入属性phone");
this.phone = phone;
}

@Override
public String toString() {
return "Person [address=" + address + ", name=" + name + ", phone="
+ phone + "]";
}

// 这是BeanFactoryAware接口方法
@Override
public void setBeanFactory(BeanFactory arg0) throws BeansException {
System.out
.println("【BeanFactoryAware接口】调用BeanFactoryAware.setBeanFactory()");
this.beanFactory = arg0;
}

// 这是BeanNameAware接口方法
@Override
public void setBeanName(String arg0) {
System.out.println("【BeanNameAware接口】调用BeanNameAware.setBeanName()");
this.beanName = arg0;
}

// 这是InitializingBean接口方法
@Override
public void afterPropertiesSet() throws Exception {
System.out
.println("【InitializingBean接口】调用InitializingBean.afterPropertiesSet()");
}

// 这是DiposibleBean接口方法
@Override
public void destroy() throws Exception {
System.out.println("【DiposibleBean接口】调用DiposibleBean.destory()");
}

// 通过<bean>的init-method属性指定的初始化方法
public void myInit() {
System.out.println("【init-method】调用<bean>的init-method属性指定的初始化方法");
}

// 通过<bean>的destroy-method属性指定的初始化方法
public void myDestory() {
System.out.println("【destroy-method】调用<bean>的destroy-method属性指定的初始化方法");
}
}

容器级生命周期接口方法

BeanPostProcessor 接口的方法

BeanPostProcessor 接口包括 2 个方法 postProcessAfterInitialization 和 postProcessBeforeInitialization,这两个方法的第一个参数都是要处理的 Bean 对象,第二个参数都是 Bean 的 name。返回值也都是要处理的 Bean 对象。这里要注意。

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor implements BeanPostProcessor {

public MyBeanPostProcessor() {
super();
System.out.println("这是BeanPostProcessor实现类构造器!!");
// TODO Auto-generated constructor stub
}

@Override
public Object postProcessAfterInitialization(Object arg0, String arg1)
throws BeansException {
System.out
.println("BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改!");
return arg0;
}

@Override
public Object postProcessBeforeInitialization(Object arg0, String arg1)
throws BeansException {
System.out
.println("BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改!");
return arg0;
}
}

InstantiationAwareBeanPostProcessor 接口的方法

InstantiationAwareBeanPostProcessor 接口本质是 BeanPostProcessor 的子接口,一般我们继承 Spring 为其提供的适配器类InstantiationAwareBeanPostProcessor Adapter 来使用它,如下:

import java.beans.PropertyDescriptor;

import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;

public class MyInstantiationAwareBeanPostProcessor extends
InstantiationAwareBeanPostProcessorAdapter {

public MyInstantiationAwareBeanPostProcessor() {
super();
System.out
.println("这是InstantiationAwareBeanPostProcessorAdapter实现类构造器!!");
}

// 接口方法、实例化Bean之前调用
@Override
public Object postProcessBeforeInstantiation(Class beanClass,
String beanName) throws BeansException {
System.out
.println("InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法");
return null;
}

// 接口方法、实例化Bean之后调用
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out
.println("InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法");
return bean;
}

// 接口方法、设置某个属性时调用
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs,
PropertyDescriptor[] pds, Object bean, String beanName)
throws BeansException {
System.out
.println("InstantiationAwareBeanPostProcessor调用postProcessPropertyValues方法");
return pvs;
}
}

工厂后处理器接口方法

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

public MyBeanFactoryPostProcessor() {
super();
System.out.println("这是BeanFactoryPostProcessor实现类构造器!!");
}

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0)
throws BeansException {
System.out
.println("BeanFactoryPostProcessor调用postProcessBeanFactory方法");
BeanDefinition bd = arg0.getBeanDefinition("person");
bd.getPropertyValues().addPropertyValue("phone", "110");
}

}

编写配置文件

配置文件如下 beans.xml,如果使用的是 ApplicationContext,处理器不用手动注册:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">

<bean id="beanPostProcessor" class="springBeanTest.MyBeanPostProcessor">
</bean>

<bean id="instantiationAwareBeanPostProcessor" class="springBeanTest.MyInstantiationAwareBeanPostProcessor">
</bean>

<bean id="beanFactoryPostProcessor" class="springBeanTest.MyBeanFactoryPostProcessor">
</bean>

<bean id="person" class="springBeanTest.Person" init-method="myInit"
destroy-method="myDestory" scope="singleton" p:name="张三" p:address="广州"
p:phone="15900000000" />

</beans>

编写测试类

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanLifeCycle {

public static void main(String[] args) {

System.out.println("现在开始初始化容器");

ApplicationContext factory = new ClassPathXmlApplicationContext("springBeanTest/beans.xml");
System.out.println("容器初始化成功");
//得到Preson,并使用
Person person = factory.getBean("person",Person.class);
System.out.println(person);

System.out.println("现在开始关闭容器!");
((ClassPathXmlApplicationContext)factory).registerShutdownHook();
}
}

关闭容器使用的是实际是 AbstractApplicationContext 的钩子方法。

Reference

参考资料 Spring Bean的生命周期(非常详细) 参考资料 5.5 Spring 中的 bean 生命周期?